package com.dc.cameraxtest.utils;

import android.graphics.Bitmap;
import android.util.Log;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author dc
 * @projectName uv
 * @description:
 * @date :2025.2.18 14:51
 */
public class ImageProcessing {
    private static final String TAG = "ImageProcessing";
    // 模糊度检测函数
    public static double calculateLaplacianVariance(Bitmap bitmap) {
        // 将Bitmap转换为OpenCV的Mat格式
        Mat matImage = new Mat();
        Utils.bitmapToMat(bitmap, matImage);

        // 将图像转换为灰度图像
        Mat grayImage = new Mat();
        Imgproc.cvtColor(matImage, grayImage, Imgproc.COLOR_BGR2GRAY);

        // 计算拉普拉斯变换
        Mat laplacianImage = new Mat();
        Imgproc.Laplacian(grayImage, laplacianImage, CvType.CV_64F);

        // 计算拉普拉斯图像的方差
        Mat laplacianAbs = new Mat();
        Core.absdiff(laplacianImage, new Scalar(0), laplacianAbs);
        Scalar mean = Core.mean(laplacianAbs);
        double variance = mean.val[0] * mean.val[0];

        // 返回方差值
        return variance;
    }

    // 判断图像是否模糊
    public static boolean checkIfImageIsBlurred(Bitmap bitmap) {
        double variance = calculateLaplacianVariance(bitmap);
        Log.e(TAG, "checkIfImageIsBlurred: variance = " + variance );
        // 设定方差阈值
        double threshold = 8.0;

        if (variance > threshold) {
//            return "清晰";
            return true;
        } else {
//            return "模糊";
            return false;
        }
    }

    public static Mat perspectiveTransform(Bitmap bitmap) {
        //将bitmap转mat
        Mat srcMat = new Mat();
        Utils.bitmapToMat(bitmap, srcMat);

        //转灰度图
        Mat grayMat = new Mat();
        Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_BGR2GRAY);

        //高斯模糊
        Mat gaussianMat = new Mat();
        Imgproc.GaussianBlur(grayMat, gaussianMat, new Size(5, 5), 1);

        //Canny 轮廓检测
        Mat edgesMat = new Mat();
        Imgproc.Canny(gaussianMat, edgesMat, 75, 200);


        //形态学
        Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
        Imgproc.morphologyEx(edgesMat, edgesMat, Imgproc.MORPH_CLOSE, kernel);

        // 膨胀，连接边缘
//        Imgproc.dilate(result, result, Mat(), Point(-1.0, -1.0), 4, 1, Scalar(1.0))
//        Imgproc.dilate(edgesMat, edgesMat,new Mat(), new Point(-1.0, -1.0), 4, 1, new Scalar(1.0));

        List<MatOfPoint> contours = new ArrayList<>();
        Mat hierarchy = new Mat();
        Imgproc.findContours(edgesMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

        // 寻找最大矩形轮廓
        double maxArea = 0;
        MatOfPoint2f maxContour = null;
        for (MatOfPoint contour: contours) {
            MatOfPoint2f contour2f = new MatOfPoint2f(contour.toArray());
            double area = Imgproc.contourArea(contour);
            if(area > maxArea) {
                MatOfPoint2f approx = new MatOfPoint2f();
                //计算轮廓的周长（或闭合曲线的弧长）。
                double epsilon = 0.02 * Imgproc.arcLength(contour2f, true);
                Imgproc.approxPolyDP(contour2f, approx, epsilon, true);
                if(approx.toArray().length == 4) {
                    // 确保是四边形
                    maxArea = area;
                    maxContour = contour2f;
                }
            }
        }
        if (maxContour == null || maxArea < 20000) {
            return srcMat; // 未找到有效轮廓
        }
        Log.e(TAG, "perspectiveTransform: maxContours = " + maxArea );
        // 新增：绘制最大轮廓到原始图像
        if (maxContour != null) {
            // 将MatOfPoint2f转换为MatOfPoint（需整数坐标）
            MatOfPoint maxContourInt = new MatOfPoint();
            maxContour.convertTo(maxContourInt, CvType.CV_32S); // 转换数据类型

            List<MatOfPoint> drawContours = new ArrayList<>();
            drawContours.add(maxContourInt);

            // 用绿色绘制轮廓，线宽3像素
            Imgproc.drawContours(srcMat, drawContours, -1, new Scalar(0, 255, 0), 3);
        }
//        return srcMat;
        // 5. 透视变换
        Point[] srcPoints = maxContour.toArray();
        Point[] orderedPoints = orderPoints(srcPoints);

        //tl, tr, br, bl
        // 示例点坐标（根据实际情况替换）
        double[] bl = {orderedPoints[3].x, orderedPoints[3].y}; // 左下角点
        double[] br = {orderedPoints[2].x, orderedPoints[2].y}; // 右下角点
        double[] tl = {orderedPoints[0].x, orderedPoints[0].y}; // 左上角点
        double[] tr = {orderedPoints[1].x, orderedPoints[1].y}; // 右上角点
        int maxWidth = calculateMaxWidth(bl, br, tl, tr);
        int maxHeight = calculateMaxHeight(bl, br, tl, tr);

        System.out.println("最大宽度: " + maxWidth);
        System.out.println("最大高度: " + maxHeight);

        Log.e(TAG, "perspectiveTransform: 最大宽度 = " + maxWidth );
        Log.e(TAG, "perspectiveTransform: 最大高度 = " + maxHeight );
        // 修改部分：使用原始图像的宽高
        // 在 orderedPoints 后添加：
      /*  double originalWidth = Math.max(
                orderedPoints[1].x - orderedPoints[0].x, // 上边宽度
                orderedPoints[2].x - orderedPoints[3].x  // 下边宽度
        );
        double originalHeight = Math.max(
                orderedPoints[3].y - orderedPoints[0].y, // 左边高度
                orderedPoints[2].y - orderedPoints[1].y  // 右边高度
        );*/

        double originalWidth = maxWidth;
        double originalHeight = maxHeight;
        // 然后使用 originalWidth/originalHeight 作为目标尺寸

        MatOfPoint2f dstPoints = new MatOfPoint2f(
                new Point(0, 0),
                new Point(originalWidth, 0),
                new Point(originalWidth, originalHeight),
                new Point(0, originalHeight)
        );

        // 计算变换矩阵
        Mat perspectiveMat = Imgproc.getPerspectiveTransform(
                new MatOfPoint2f(orderedPoints),
                dstPoints
        );
        // 应用变换
        Mat dstMat = new Mat();
        Imgproc.warpPerspective(srcMat, dstMat, perspectiveMat, new Size(originalWidth, originalHeight));

        return dstMat;
    }

    private static Point[] orderPoints(Point[] points) {
        Arrays.sort(points, (p1, p2) -> (int) (p1.x - p2.x)); // 按x排序
        Point[] left = {points[0], points[1]};
        Point[] right = {points[2], points[3]};
        // 左上（y较小）
        Arrays.sort(left, (p1, p2) -> (int) (p1.y - p2.y));
        Point tl = left[0];
        Point bl = left[1];
        // 右上（y较小）
        Arrays.sort(right, (p1, p2) -> (int) (p1.y - p2.y));
        Point tr = right[0];
        Point br = right[1];
        return new Point[]{tl, tr, br, bl};
    }



    // 计算最大宽度
    public static int calculateMaxWidth(double[] bl, double[] br, double[] tl, double[] tr) {
        // 计算底边(br到bl)和顶边(tr到tl)的宽度
        double widthA = euclideanDistance(br, bl);
        double widthB = euclideanDistance(tr, tl);
        return Math.max((int) widthA, (int) widthB);
    }

    // 计算最大高度
    public static int calculateMaxHeight(double[] bl, double[] br, double[] tl, double[] tr) {
        // 计算右侧(tr到br)和左侧(tl到bl)的高度
        double heightA = euclideanDistance(tr, br);
        double heightB = euclideanDistance(tl, bl);
        return Math.max((int) heightA, (int) heightB);
    }

    // 计算两点之间的欧几里得距离
    private static double euclideanDistance(double[] point1, double[] point2) {
        double dx = point1[0] - point2[0];
        double dy = point1[1] - point2[1];
        return Math.sqrt(dx * dx + dy * dy);
    }
}
